"""
@File    : get_ip_by_ecmid.py
@Author  : timo.tan
@Time    : 2025/07/30 11:36 
"""

import requests
from typing import Dict, List, Any, Optional, Tuple
from tools.log_util import INFO, ERROR, WARNING
from concurrent.futures import ThreadPoolExecutor, as_completed
import time

# API配置
API_BASE_URL = 'https://cgboss.yuntiancloud.com/api'
DEFAULT_PAGE_SIZE = 100


def get_auth_token() -> str:
    """获取认证Token，后续可以改为从配置文件或环境变量获取"""
    return 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEzMjk4LCJpc3MiOiJjZ2Jvc3MiLCJleHAiOjE3NTU3NDY5OTUsIm5iZiI6MTc1MzE1NDk5NSwiaWF0IjoxNzUzMTU0OTk1fQ.lZfw2ESYhSWwM0GT'


def get_all_vms_by_ecmid(ecm_id: int, show_detail: bool = False) -> Tuple[Optional[List[Dict]], Optional[str]]:
    """
    通过 ECM ID 获取所有虚拟机数据
    
    Args:
        ecm_id: ECM ID
        show_detail: 是否显示详细信息
    
    Returns:
        Tuple[Optional[List[Dict]], Optional[str]]: (虚拟机列表, 错误信息)
    """
    try:
        url = f'{API_BASE_URL}/cginstance/v1/vm/list'
        headers = {'Authorization': get_auth_token()}

        all_vms = []
        page_no = 1

        while True:
            data = {
                "page": {"no": page_no, "size": DEFAULT_PAGE_SIZE},
                "ecns": [str(ecm_id)],
                "systemLabels": [],
                "customizeLabels": [],
                "projectIds": [],
                "resourceType": 1,
                "arches": ["X86"]
            }

            response = requests.post(url=url, headers=headers, json=data, timeout=30)

            if not response.ok:
                error_msg = f"API请求失败: HTTP {response.status_code}, {response.text}"
                ERROR.logger.error(error_msg)
                return None, error_msg

            result = response.json()

            if show_detail:
                INFO.logger.info(f"第{page_no}页数据: {result}")

            # 获取数据
            body = result.get('body', {})
            current_vms = body.get('vms', [])
            total = body.get('total', 0)

            if not current_vms:  # 没有更多数据了
                break

            all_vms.extend(current_vms)

            # 检查是否需要继续获取下一页
            if len(all_vms) >= total:
                break

            page_no += 1

        return all_vms, None

    except requests.RequestException as e:
        error_msg = f"网络请求异常: {str(e)}"
        ERROR.logger.error(error_msg)
        return None, error_msg
    except Exception as e:
        error_msg = f"未知错误: {str(e)}"
        ERROR.logger.error(error_msg)
        return None, error_msg


def get_vm_by_vmid(vmid: str, show_detail: bool = False) -> Tuple[Optional[Dict], Optional[str]]:
    """
    通过 VMID 直接获取虚拟机信息
    
    Args:
        vmid: 虚拟机ID
        show_detail: 是否显示详细信息
    
    Returns:
        Tuple[Optional[Dict], Optional[str]]: (虚拟机信息, 错误信息)
    """
    try:
        url = f'{API_BASE_URL}/cginstance/v1/vm/list'
        headers = {'Authorization': get_auth_token()}

        # 通过vmid查询，不需要指定ecns
        data = {
            "page": {"no": 1, "size": DEFAULT_PAGE_SIZE},
            "vmids": [str(vmid)],  # 直接通过vmid查询
            "systemLabels": [],
            "customizeLabels": [],
            "projectIds": [],
            "resourceType": 1,
            "arches": ["X86"]
        }

        response = requests.post(url=url, headers=headers, json=data, timeout=30)

        if not response.ok:
            error_msg = f"API请求失败: HTTP {response.status_code}, {response.text}"
            ERROR.logger.error(error_msg)
            return None, error_msg

        result = response.json()

        if show_detail:
            INFO.logger.info(f"VMID {vmid} 查询结果: {result}")

        # 获取数据
        body = result.get('body', {})
        vms = body.get('vms', [])

        if not vms:
            return None, f"未找到VMID为 {vmid} 的虚拟机"

        # 返回第一个匹配的虚拟机（通常只有一个）
        return vms[0], None

    except requests.RequestException as e:
        error_msg = f"网络请求异常: {str(e)}"
        ERROR.logger.error(error_msg)
        return None, error_msg
    except Exception as e:
        error_msg = f"未知错误: {str(e)}"
        ERROR.logger.error(error_msg)
        return None, error_msg


def get_ip_by_vmid(vmid: str) -> Tuple[Optional[str], Optional[str]]:
    """
    通过 VMID 获取对应的IP地址（独立于ECM）
    
    Args:
        vmid: 虚拟机ID
    
    Returns:
        Tuple[Optional[str], Optional[str]]: (IP地址, 错误信息)
    """
    vm, error = get_vm_by_vmid(vmid)
    if error:
        return None, error

    ip_address = vm.get('ipAddress')
    if not ip_address:
        return None, f"虚拟机 {vmid} 没有分配IP地址"

    return ip_address, None


def get_multiple_ips_by_vmids_independent(vmid_list: List[str]) -> Tuple[Optional[Dict[str, str]], Optional[List[str]]]:
    """
    通过多个VMID获取对应的IP地址（独立于ECM，使用批量查询）
    
    Args:
        vmid_list: 虚拟机ID列表
    
    Returns:
        Tuple[Optional[Dict[str, str]], Optional[List[str]]]: ({vmid: ip}, 错误信息列表)
    """
    try:
        url = f'{API_BASE_URL}/cginstance/v1/vm/list'
        headers = {'Authorization': get_auth_token()}

        # 批量查询所有vmid
        data = {
            "page": {"no": 1, "size": max(len(vmid_list), DEFAULT_PAGE_SIZE)},
            "vmids": [str(vmid) for vmid in vmid_list],  # 一次性传入所有vmid
            "systemLabels": [],
            "customizeLabels": [],
            "projectIds": [],
            "resourceType": 1,
            "arches": ["X86"]
        }

        response = requests.post(url=url, headers=headers, json=data, timeout=60)  # 增加超时时间

        if not response.ok:
            error_msg = f"API请求失败: HTTP {response.status_code}, {response.text}"
            ERROR.logger.error(error_msg)
            return None, [error_msg]

        result = response.json()
        body = result.get('body', {})
        vms = body.get('vms', [])

        # 构建vmid到IP的映射
        vmid_ip_map = {}
        found_vmids = set()
        
        # 先处理查询到的虚拟机
        for vm in vms:
            vmid = str(vm.get('vmid'))
            ip_address = vm.get('ipAddress')
            if ip_address:
                vmid_ip_map[vmid] = ip_address
            else:
                vmid_ip_map[vmid] = "无IP地址"
            found_vmids.add(vmid)

        # 处理未找到的虚拟机
        errors = []
        for vmid in vmid_list:
            vmid_str = str(vmid)
            if vmid_str not in found_vmids:
                vmid_ip_map[vmid_str] = "查询失败"
                errors.append(f"VMID {vmid}: 未找到虚拟机")

        return vmid_ip_map, errors if errors else None

    except requests.RequestException as e:
        error_msg = f"网络请求异常: {str(e)}"
        ERROR.logger.error(error_msg)
        return None, [error_msg]
    except Exception as e:
        error_msg = f"未知错误: {str(e)}"
        ERROR.logger.error(error_msg)
        return None, [error_msg]


def get_ip_string_by_vmids(vmid_list: List[str]) -> Tuple[Optional[str], Optional[List[str]]]:
    """
    通过多个VMID获取逗号分隔的IP地址字符串（保持输入顺序）
    
    Args:
        vmid_list: 虚拟机ID列表
    
    Returns:
        Tuple[Optional[str], Optional[List[str]]]: (逗号分隔的IP字符串, 错误信息列表)
    """
    vmid_ip_map, errors = get_multiple_ips_by_vmids_independent(vmid_list)
    if not vmid_ip_map:
        return None, errors
    
    # 按照输入VMID的顺序获取IP地址
    ordered_ips = []
    for vmid in vmid_list:
        vmid_str = str(vmid)
        ip = vmid_ip_map.get(vmid_str)
        if ip and ip != "查询失败" and ip != "无IP地址":
            ordered_ips.append(ip)
    
    if not ordered_ips:
        return "", errors
    
    return ", ".join(ordered_ips), errors


def get_ip_list_by_ecmid(ecm_id: int, include_empty: bool = False) -> Tuple[Optional[List[str]], Optional[str]]:
    """
    通过 ECM ID 获取所有IP地址列表
    
    Args:
        ecm_id: ECM ID
        include_empty: 是否包含空IP地址
    
    Returns:
        Tuple[Optional[List[str]], Optional[str]]: (IP地址列表, 错误信息)
    """
    vms, error = get_all_vms_by_ecmid(ecm_id)
    if error:
        return None, error

    if not vms:
        return [], None

    # 提取所有IP地址
    ip_list = []
    for vm in vms:
        ip_address = vm.get('ipAddress')
        if ip_address:
            ip_list.append(ip_address)
        elif include_empty:
            ip_list.append('')  # 如果需要包含空IP，添加空字符串

    # 去重并保持顺序
    unique_ips = []
    seen = set()
    for ip in ip_list:
        if ip not in seen:
            unique_ips.append(ip)
            seen.add(ip)

    return unique_ips, None


def get_ip_with_vm_info_by_ecmid(ecm_id: int) -> Tuple[Optional[List[Dict[str, Any]]], Optional[str]]:
    """
    通过 ECM ID 获取IP地址及对应的虚拟机信息
    
    Args:
        ecm_id: ECM ID
    
    Returns:
        Tuple[Optional[List[Dict]], Optional[str]]: (包含IP和VM信息的列表, 错误信息)
    """
    vms, error = get_all_vms_by_ecmid(ecm_id)
    if error:
        return None, error

    if not vms:
        return [], None

    # 提取IP地址及相关信息
    ip_info_list = []
    for vm in vms:
        ip_address = vm.get('ipAddress')
        if ip_address:  # 只包含有IP地址的虚拟机
            vm_info = {
                'ip_address': ip_address,
                'vmid': vm.get('vmid'),
                'project_name': vm.get('projectName'),
                'os_state': vm.get('osState'),
                'cpu_count': vm.get('cpuCount'),
                'memory_size': vm.get('memorySize')
            }
            ip_info_list.append(vm_info)

    return ip_info_list, None


def get_ip_string_by_ecmid(ecm_id: int) -> Tuple[Optional[str], Optional[str]]:
    """
    通过 ECM ID 获取逗号分隔的IP地址字符串
    
    Args:
        ecm_id: ECM ID
    
    Returns:
        Tuple[Optional[str], Optional[str]]: (逗号分隔的IP字符串, 错误信息)
    """
    ip_list, error = get_ip_list_by_ecmid(ecm_id)
    if error:
        return None, error

    if not ip_list:
        return "", None

    # 返回逗号分隔的IP字符串
    return ", ".join(ip_list), None


def get_ip_by_vmid_in_ecm(vmid: str, ecm_id: int) -> Tuple[Optional[str], Optional[str]]:
    """
    在指定ECM中通过VMID获取对应的IP地址（保留原功能）
    
    Args:
        vmid: 虚拟机ID
        ecm_id: ECM ID
    
    Returns:
        Tuple[Optional[str], Optional[str]]: (IP地址, 错误信息)
    """
    vms, error = get_all_vms_by_ecmid(ecm_id)
    if error:
        return None, error

    if not vms:
        return None, f"ECM ID {ecm_id} 中未找到任何虚拟机"

    # 在虚拟机列表中查找指定的vmid
    for vm in vms:
        if str(vm.get('vmid')) == str(vmid):
            ip_address = vm.get('ipAddress')
            if ip_address:
                return ip_address, None
            else:
                return None, f"虚拟机 {vmid} 没有分配IP地址"

    return None, f"在ECM {ecm_id} 中未找到虚拟机 {vmid}"


def get_ip_by_vmid_in_vm_list(vmid: str, vm_list: List[Dict]) -> Optional[str]:
    """
    在虚拟机列表中通过VMID获取对应的IP地址
    
    Args:
        vmid: 虚拟机ID
        vm_list: 虚拟机列表
    
    Returns:
        Optional[str]: IP地址，未找到返回None
    """
    for vm in vm_list:
        if str(vm.get('vmid')) == str(vmid):
            return vm.get('ipAddress')
    return None


def get_multiple_ips_by_vmids(vmid_list: List[str], ecm_id: int) -> Tuple[Optional[Dict[str, str]], Optional[str]]:
    """
    在指定ECM中通过多个VMID获取对应的IP地址
    
    Args:
        vmid_list: 虚拟机ID列表
        ecm_id: ECM ID
    
    Returns:
        Tuple[Optional[Dict[str, str]], Optional[str]]: ({vmid: ip}, 错误信息)
    """
    vms, error = get_all_vms_by_ecmid(ecm_id)
    if error:
        return None, error

    if not vms:
        return None, f"ECM ID {ecm_id} 中未找到任何虚拟机"

    # 构建vmid到IP的映射
    vmid_ip_map = {}
    for vmid in vmid_list:
        ip = get_ip_by_vmid_in_vm_list(str(vmid), vms)
        vmid_ip_map[str(vmid)] = ip if ip else "未找到"

    return vmid_ip_map, None


def print_vmid_ip_mapping(vmid_ip_map: Dict[str, str], ecm_id: int):
    """打印VMID到IP的映射关系"""
    print(f"\n📋 ECM ID {ecm_id} 中的VMID-IP映射:")
    print("─" * 40)
    print(f"{'VMID':<15} {'IP地址':<15}")
    print("─" * 40)

    for vmid, ip in vmid_ip_map.items():
        print(f"{vmid:<15} {ip:<15}")

    print("─" * 40 + "\n")


def print_ip_list(ip_list: List[str], ecm_id: int):
    """格式化打印IP列表"""
    print("\n" + "═" * 60)
    print(f"🔍 ECM ID: {ecm_id} 的所有IP地址")
    print("═" * 60)

    if not ip_list:
        print("⚠️ 未找到任何IP地址")
        return

    print(f"📊 总计: {len(ip_list)} 个IP地址\n")

    for i, ip in enumerate(ip_list, 1):
        print(f"  {i:2d}. {ip}")

    print("\n" + "═" * 60 + "\n")


def main_ecm(ecm_id: int):
    """通过ECM ID获取所有IP地址的主函数"""
    print(f"\n🚀 开始获取 ECM ID: {ecm_id} 的所有IP地址...\n")

    # 获取逗号分隔的IP字符串
    ip_string, error = get_ip_string_by_ecmid(ecm_id)
    if error:
        print(f"❌ 错误: {error}")
        return

    if not ip_string:
        print("⚠️ 未找到任何IP地址")
        return

    print(f"📋 ECM ID {ecm_id} 的所有IP地址:")
    print(ip_string)
    print()

    return ip_string


def main_vmid(vmid: str):
    """通过VMID获取IP地址的主函数"""
    print(f"\n🚀 开始获取 VMID: {vmid} 对应的IP地址...\n")

    ip, error = get_ip_by_vmid(vmid)
    if error:
        print(f"❌ 错误: {error}")
        return

    print(f"📋 VMID {vmid} 对应的IP地址:")
    print(ip)
    print()

    return ip


def main_vmids(vmid_list: List[str]):
    """通过多个VMID获取IP地址的主函数"""
    print(f"\n🚀 开始获取多个VMID对应的IP地址...\n")
    print(f"VMID列表: {vmid_list}")

    ip_string, errors = get_ip_string_by_vmids(vmid_list)
    if errors:
        print("⚠️ 部分查询失败:")
        for error in errors:
            print(f"   - {error}")

    if not ip_string:
        print("❌ 未找到任何有效的IP地址")
        return

    print(f"\n📋 成功获取的IP地址(逗号分隔):")
    print(ip_string)
    print()

    return ip_string


def main(ecm_id: int):
    """主函数 - 保持向后兼容"""
    return main_ecm(ecm_id)


def demo_vmid_query_in_ecm(ecm_id: int, vmid: str):
    """演示在指定ECM中通过VMID获取IP功能"""
    print(f"\n🔍 演示在指定ECM中通过VMID获取IP功能")
    print(f"ECM ID: {ecm_id}, VMID: {vmid}")
    print("═" * 50)

    # 获取单个VMID对应的IP
    ip, error = get_ip_by_vmid_in_ecm(vmid, ecm_id)
    if error:
        print(f"❌ 错误: {error}")
    else:
        print(f"✅ VMID {vmid} 对应的IP地址: {ip}")

    print("═" * 50 + "\n")


def demo_multiple_vmids_query_in_ecm(ecm_id: int, vmid_list: List[str]):
    """演示在指定ECM中通过多个VMID获取IP功能"""
    print(f"\n🔍 演示在指定ECM中通过多个VMID获取IP功能")
    print(f"ECM ID: {ecm_id}")
    print(f"VMID列表: {vmid_list}")
    print("═" * 60)

    # 获取多个VMID对应的IP映射
    vmid_ip_map, error = get_multiple_ips_by_vmids(vmid_list, ecm_id)
    if error:
        print(f"❌ 错误: {error}")
        return

    # 打印映射关系
    print_vmid_ip_mapping(vmid_ip_map, ecm_id)

    # 也输出逗号分隔的IP列表
    valid_ips = [ip for ip in vmid_ip_map.values() if ip != "未找到" and ip]
    if valid_ips:
        print(f"📋 找到的IP地址(逗号分隔): {', '.join(valid_ips)}")
    else:
        print("⚠️ 未找到任何有效的IP地址")

    print("═" * 60 + "\n")


def demo_vmid_query_independent(vmid: str):
    """演示通过VMID独立获取IP功能（不需要ECM ID）"""
    print(f"\n🔍 演示通过VMID独立获取IP功能")
    print(f"VMID: {vmid}")
    print("═" * 50)

    # 获取单个VMID对应的IP
    ip, error = get_ip_by_vmid(vmid)
    if error:
        print(f"❌ 错误: {error}")
    else:
        print(f"✅ VMID {vmid} 对应的IP地址: {ip}")

    print("═" * 50 + "\n")


def demo_multiple_vmids_query_independent(vmid_list: List[int]):
    """演示通过多个VMID独立获取IP功能（不需要ECM ID）"""
    print(f"\n🔍 批量查询多个VMID的IP地址")
    print(f"查询的VMID数量: {len(vmid_list)}")
    print("═" * 50)
    
    # 添加计时
    import time
    start_time = time.time()
    
    # 获取逗号分隔的IP字符串
    ip_string, errors = get_ip_string_by_vmids(vmid_list)
    
    end_time = time.time()
    elapsed_time = end_time - start_time
    
    print(f"⏱️  查询耗时: {elapsed_time:.2f} 秒（批量查询）")
    
    # 显示错误信息（如果有的话）
    if errors:
        print(f"⚠️  部分查询失败 ({len(errors)}个):")
        for error in errors[:3]:  # 只显示前3个错误，避免输出过多
            print(f"   - {error}")
        if len(errors) > 3:
            print(f"   - ... 还有 {len(errors) - 3} 个错误")
    
    if not ip_string:
        print("❌ 未找到任何有效的IP地址")
        return ""
    
    # 统计成功查询的数量
    success_count = len([ip for ip in ip_string.split(", ") if ip.strip()])
    print(f"✅ 成功查询: {success_count}/{len(vmid_list)} 个虚拟机")
    
    print(f"\n📋 获取到的IP地址:")
    print(ip_string)
    print("═" * 50 + "\n")
    
    return ip_string


def get_multiple_vms_by_vmids(vmid_list: List[str], show_detail: bool = False) -> Tuple[Optional[List[Dict]], Optional[str]]:
    """
    通过多个VMID批量获取虚拟机信息（一次API调用）
    
    Args:
        vmid_list: 虚拟机ID列表
        show_detail: 是否显示详细信息
    
    Returns:
        Tuple[Optional[List[Dict]], Optional[str]]: (虚拟机列表, 错误信息)
    """
    try:
        url = f'{API_BASE_URL}/cginstance/v1/vm/list'
        headers = {'Authorization': get_auth_token()}

        # 一次性查询多个vmid
        data = {
            "page": {"no": 1, "size": len(vmid_list) if len(vmid_list) <= DEFAULT_PAGE_SIZE else DEFAULT_PAGE_SIZE},
            "vmids": [str(vmid) for vmid in vmid_list],  # 批量查询
            "systemLabels": [],
            "customizeLabels": [],
            "projectIds": [],
            "resourceType": 1,
            "arches": ["X86"]
        }

        response = requests.post(url=url, headers=headers, json=data, timeout=30)

        if not response.ok:
            error_msg = f"API请求失败: HTTP {response.status_code}, {response.text}"
            ERROR.logger.error(error_msg)
            return None, error_msg

        result = response.json()

        if show_detail:
            INFO.logger.info(f"批量查询VMID结果: {result}")

        # 获取数据
        body = result.get('body', {})
        vms = body.get('vms', [])

        return vms, None

    except requests.RequestException as e:
        error_msg = f"网络请求异常: {str(e)}"
        ERROR.logger.error(error_msg)
        return None, error_msg
    except Exception as e:
        error_msg = f"未知错误: {str(e)}"
        ERROR.logger.error(error_msg)
        return None, error_msg

def get_ip_string_by_vmids_fast(vmid_list: List[str]) -> Tuple[Optional[str], Optional[str]]:
    """
    通过多个VMID快速获取逗号分隔的IP地址字符串（批量查询）
    
    Args:
        vmid_list: 虚拟机ID列表
    
    Returns:
        Tuple[Optional[str], Optional[str]]: (逗号分隔的IP字符串, 错误信息)
    """
    vms, error = get_multiple_vms_by_vmids(vmid_list)
    if error:
        return None, error
    
    if not vms:
        return "", None
    
    # 提取IP地址
    ip_list = []
    for vm in vms:
        ip_address = vm.get('ipAddress')
        if ip_address:
            ip_list.append(ip_address)
    
    if not ip_list:
        return "", None
    
    return ", ".join(ip_list), None


if __name__ == '__main__':
    # main_ecm(ecm_id=7503)
    # 演示通过VMID独立获取IP (需要根据实际情况修改VMID)
    demo_multiple_vmids_query_independent(
        vmid_list=[105667,105513,105475,105467,105747,105594,105590,105530,105750,105656,105577,105545,105517,105497,105496,105483,105478,105802])
